package controllers

import (
	"gouniapp/configs"
	"net/http"
	"fmt"
	"time"
	"log"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"errors"
)

type ProductQuery struct {
	Page        int    `json:"page"`
	PageSize    int    `json:"pageSize"`
	Search      string `json:"search"`
	IsAvailable *bool `json:"is_available"` // 是否后台访问，使用指针类型允许空值
}

// 商品列表响应结构
type ProductListResponse struct {
	Items []configs.Product `json:"items"`
	Total int64             `json:"total"`
}

// 分页获取商品列表-前后台通用
func GetProducts(c *gin.Context) {
	var query ProductQuery
	if err := c.ShouldBindJSON(&query); err != nil {
		JsonResponse(c, http.StatusBadRequest, "请求参数错误", nil)
		return
	}
	// 限制最大每页数量
	if query.PageSize > 100 {
		query.PageSize = 100
	}
	// 初始化查询
	dbQuery := configs.DB.Model(&configs.Product{}).Order("id DESC")
	// 搜索条件
	if query.Search != "" {
		search := "%" + query.Search + "%"
		dbQuery.Where("name LIKE ? OR description LIKE ?", search, search)
	}
	if query.IsAvailable != nil {
        currentUser := GetCurrentUser(c) //后台显示全部
        if currentUser == nil || currentUser.Role != "admin" {
            JsonResponse(c, http.StatusForbidden, "无权限访问", nil)
            return
        }
    } else {
        dbQuery.Where("is_available = ?", true) //前台只显示上架的
    }
	// 查询总数
	var total int64
	if err := dbQuery.Count(&total).Error; err != nil {
		JsonResponse(c, http.StatusInternalServerError, "查询总数失败", nil)
		return
	}
	// 分页查询
	var products []configs.Product
	err := dbQuery.Scopes(configs.Paginate(query.Page, query.PageSize)).Find(&products).Error
	if err != nil {
		JsonResponse(c, http.StatusInternalServerError, "查询数据失败", nil)
		return
	}
	JsonResponse(c, http.StatusOK, "Success", ProductListResponse{
		Items: products,
		Total: total,
	})
}

// 创建商品
func CreateProduct(c *gin.Context) {
    // 权限验证
    currentUser := GetCurrentUser(c)
    if currentUser == nil || currentUser.Role != "admin" {
        JsonResponse(c, http.StatusForbidden, "无权限操作", nil)
        return
    }
    // 参数绑定
    var req configs.Product
    if err := c.ShouldBindJSON(&req); err != nil {
        JsonResponse(c, http.StatusBadRequest, "参数错误: "+err.Error(), nil)
        return
    }
    // 检查商品名称唯一性
    var existProduct configs.Product
    if err := configs.DB.Where("name = ?", req.Name).First(&existProduct).Error; 
        err == nil {
        JsonResponse(c, http.StatusConflict, "商品名称已存在", nil)
        return
    } else if !errors.Is(err, gorm.ErrRecordNotFound) {
        JsonResponse(c, http.StatusInternalServerError, "系统错误", nil)
        return
    }
    if req.HiddenContent == "" {
        JsonResponse(c, http.StatusInternalServerError, "付费内容不得为空", nil)
        return
    }
    // 数据库创建
    if err := configs.DB.Create(&req).Error; err != nil {
        JsonResponse(c, http.StatusInternalServerError, "创建失败", nil)
        return
    }
    // 返回创建结果（包含生成字段）
    JsonResponse(c, http.StatusOK, "创建成功", req)
}

// 更新商品
func UpdateProduct(c *gin.Context) {
    // 权限验证
    currentUser := GetCurrentUser(c)
    if currentUser == nil || currentUser.Role != "admin" {
        JsonResponse(c, http.StatusForbidden, "无权限操作", nil)
        return
    }
    // 参数绑定
    productID := c.Param("id")
    var req configs.Product
    if err := c.ShouldBindJSON(&req); err != nil {
        JsonResponse(c, http.StatusBadRequest, "参数错误: "+err.Error(), nil)
        return
    }
    // 获取现有商品
    var product configs.Product
    if err := configs.DB.First(&product, productID).Error; err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            JsonResponse(c, http.StatusNotFound, "商品不存在", nil)
        } else {
            JsonResponse(c, http.StatusInternalServerError, "系统错误", nil)
        }
        return
    }
    // 名称唯一性检查（如果修改了名称）
    if req.Name != "" && req.Name != product.Name {
        var existProduct configs.Product
        if err := configs.DB.Where("name = ?", req.Name).First(&existProduct).Error; 
            err == nil {
            JsonResponse(c, http.StatusConflict, "商品名称已存在", nil)
            return
        } else if !errors.Is(err, gorm.ErrRecordNotFound) {
            JsonResponse(c, http.StatusInternalServerError, "系统错误", nil)
            return
        }
    }
    if req.HiddenContent == "" {
        JsonResponse(c, http.StatusInternalServerError, "付费内容不得为空", nil)
        return
    }
    if err := configs.DB.Select("Name", "Photo", "Description", "Points", "HiddenContent", "Stock", "IsAvailable").Updates(&req).Error; err != nil {
        JsonResponse(c, http.StatusInternalServerError, "更新失败", nil)
        return
    }
    JsonResponse(c, http.StatusOK, "更新成功", req)
}


// 删除商品
func DeleteProduct(c *gin.Context) {
	currentUser := GetCurrentUser(c)
	if currentUser == nil || currentUser.Role != "admin" {
		JsonResponse(c, http.StatusForbidden, "无权限操作", nil)
		return
	}
	productID := c.Param("id")
	var product configs.Product
	if err := configs.DB.First(&product, productID).Error; err != nil {
		JsonResponse(c, http.StatusNotFound, "商品不存在", nil)
		return
	}
	if err := configs.DB.Delete(&product).Error; err != nil {
		JsonResponse(c, http.StatusInternalServerError, "删除失败", nil)
		return
	}
	JsonResponse(c, http.StatusOK, "删除成功", nil)
}

// 获取指定商品，需要判断用户是否已经购买，已购买则返回HiddenContent
func GetProductDetail(c *gin.Context) {
    // 参数校验
    id := c.Param("id")
    if id == "" {
        JsonResponse(c, http.StatusBadRequest, "参数不正确", nil)
        return
    }
    // 验证ID格式
    var productIDUint uint
    if _, err := fmt.Sscanf(id, "%d", &productIDUint); err != nil {
        JsonResponse(c, http.StatusBadRequest, "商品ID必须为有效数字", nil)
        return
    }
    // 获取商品基础信息
    var product configs.Product
    if err := configs.DB.First(&product, productIDUint).Error; err != nil {
        JsonResponse(c, http.StatusNotFound, "商品不存在", nil)
        return
    }
    //检查用户是否已购买
    var purchase configs.Purchase
    currentUser := GetCurrentUser(c)
    if currentUser != nil && currentUser.ID > 0 {
        configs.DB.Where("user_id = ? AND product_id = ?", currentUser.ID, productIDUint).First(&purchase)
        fmt.Println("商品id", purchase.ID)
    }
    if purchase.ID  == 0 {
        fmt.Println(product.HiddenContent)
        product.HiddenContent = "" // 未购买，清空隐藏内容
    } else if product.HiddenContent == "" {
        product.HiddenContent = "暂无内容"
    }
    JsonResponse(c, http.StatusOK, "获取成功", product)
}

// 购买商品
func PurchaseProduct(c *gin.Context) {
    currentUser := GetCurrentUser(c)
    if currentUser == nil {
        JsonResponse(c, http.StatusUnauthorized, "请重新登录", nil)
        return
    }
    // 获取并验证商品ID
    productID := c.Param("id")
    if productID == "" {
        JsonResponse(c, http.StatusBadRequest, "商品ID不能为空", nil)
        return
    }
    // 验证ID格式
    var productIDUint uint
    if _, err := fmt.Sscanf(productID, "%d", &productIDUint); err != nil {
        JsonResponse(c, http.StatusBadRequest, "商品ID必须为有效数字", nil)
        return
    }
    var product configs.Product
    // 定义事务返回结果结构体
    type purchaseResult struct {
        RemainingPoints uint
        LatestStock     uint
        PurchaseID      uint
        HiddenContent   string
    }
    var result purchaseResult
    // 自定义错误类型
    var (
        ErrProductNotFound   = errors.New("商品不存在")
        ErrUserState        = errors.New("用户状态异常")
        ErrInsufficientPoints = errors.New("积分不足")
        ErrOutOfStock       = errors.New("库存不足")
    )
    err := configs.DB.Transaction(func(tx *gorm.DB) error {
        // 1. 锁定并获取商品（写锁）
        if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&product, productIDUint).Error; err != nil {
            if errors.Is(err, gorm.ErrRecordNotFound) {
                return ErrProductNotFound
            }
            return fmt.Errorf("锁定商品失败: %w", err)
        }
        // 2. 锁定用户记录（写锁）
        var user configs.User
        if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&user, currentUser.ID).Error; err != nil {
            if errors.Is(err, gorm.ErrRecordNotFound) {
                return ErrUserState
            }
            return fmt.Errorf("锁定用户失败: %w", err)
        }
        // 3. 业务规则验证
        if user.Points < product.Points {
            return ErrInsufficientPoints
        }
        if product.Stock < 1 {
            return ErrOutOfStock
        }
        // 4. 执行数据修改
        user.Points -= product.Points
        if err := tx.Save(&user).Error; err != nil {
            return fmt.Errorf("更新用户积分失败: %w", err)
        }
        // 使用原子操作更新库存
        if err := tx.Model(&product).
            Update("stock", gorm.Expr("stock - 1")).Error; err != nil {
            return fmt.Errorf("更新库存失败: %w", err)
        }
        // 5. 获取最新库存（需显式查询）
        if err := tx.First(&product, productIDUint).Error; err != nil {
            return fmt.Errorf("获取最新库存失败: %w", err)
        }
        // 6. 创建购买记录
        purchase := configs.Purchase{
            UserID:        currentUser.ID,
            ProductID:     product.ID,
            Quantity:      1,
            HiddenContent: product.HiddenContent,
        }
        if err := tx.Create(&purchase).Error; err != nil {
            return fmt.Errorf("创建购买记录失败: %w", err)
        }
        // 7. 准备返回数据
        result = purchaseResult{
            RemainingPoints: user.Points,
            LatestStock:     product.Stock,
            PurchaseID:      purchase.ID,
            HiddenContent:   product.HiddenContent,
        }
        // 8. 清除用户缓存
        userCacheKey := fmt.Sprintf("user:%d", user.ID)
        configs.CRdb.Delete(userCacheKey)
        return nil
    })
    // 错误处理
    if err != nil {
        switch {
        case errors.Is(err, ErrInsufficientPoints),
             errors.Is(err, ErrOutOfStock),
             errors.Is(err, ErrProductNotFound):
            JsonResponse(c, http.StatusBadRequest, err.Error(), nil)
        case errors.Is(err, ErrUserState):
            JsonResponse(c, http.StatusUnauthorized, err.Error(), nil)
        default:
            log.Printf("购买失败 - 错误详情: %+v", err)
            JsonResponse(c, http.StatusInternalServerError, "系统繁忙，请稍后再试", gin.H{
                "request_id": c.GetString("x-request-id"),
            })
        }
        return
    }
    JsonResponse(c, http.StatusOK, "购买成功", gin.H{
        "purchase_id":      result.PurchaseID,
        "remaining_points": result.RemainingPoints, //用户积分
        "hidden_content":   result.HiddenContent,   //隐藏内容
        "current_stock":    result.LatestStock,     //库存
    })
}

// 构造响应数据
type PurchaseResponse struct {
	ID          uint      `json:"id"`
	ProductName string    `json:"product_name"`
	UserName    string    `json:"user_name"`
	Quantity    uint      `json:"quantity"`
	TotalPoints uint      `json:"total_points"`
	CreatedAt   time.Time `json:"created_at"`
}
// 购买记录列表响应结构
type PurchaseListResponse struct {
	Items []PurchaseResponse    `json:"items"`
	Total int64                 `json:"total"`
}

//后台查看购买记录
func GetPurchases(c *gin.Context) {
	var query configs.FormQuery
	if err := c.ShouldBindJSON(&query); err != nil {
		JsonResponse(c, http.StatusBadRequest, "请求参数错误", nil)
		return
	}
	if query.PageSize > 100 {
		query.PageSize = 100
	}
	dbQuery := configs.DB.Model(&configs.Purchase{}).Preload("Product").Preload("User").Order("created_at DESC")
	var total int64
	if err := dbQuery.Count(&total).Error; err != nil {
		JsonResponse(c, http.StatusInternalServerError, "查询总数失败", nil)
		return
	}
	var purchases []configs.Purchase
	err := dbQuery.Scopes(configs.Paginate(query.Page, query.PageSize)).Find(&purchases).Error
	if err != nil {
		JsonResponse(c, http.StatusInternalServerError, "查询数据失败", nil)
		return
	}
	var response []PurchaseResponse
	for _, p := range purchases {
		response = append(response, PurchaseResponse{
			ID:          p.ID,
			ProductName: p.Product.Name,
			UserName:    p.User.Name, //购买人
			Quantity:    p.Quantity,
			TotalPoints: p.Product.Points * p.Quantity,
			CreatedAt:   p.CreatedAt,
		})
	}
	JsonResponse(c, http.StatusOK, "Success", PurchaseListResponse{
		Items: response,
		Total: total,
	})
}

// 前台分页获取用户购买记录及充值记录
func GetPurchaseHistory(c *gin.Context) {
	currentUser := GetCurrentUser(c)
	if currentUser == nil {
		JsonResponse(c, http.StatusUnauthorized, "请重新登录", nil)
		return
	}
	// 使用标准请求参数结构
	type Request struct {
		Page     int    `json:"page" binding:"required,min=1"`
		PageSize int    `json:"pageSize" binding:"required,min=1,max=100"`
		Type     string `json:"type" binding:"required,oneof=product points"` // 修改参数名为type
	}
	var req Request
	if err := c.ShouldBindJSON(&req); err != nil {
		JsonResponse(c, http.StatusBadRequest, "请求参数错误："+err.Error(), nil)
		return
	}
	// 统一响应结构
	type OrderItem struct {
		ID          uint      `json:"id"`
		OrderType   string    `json:"order_type"` // 明确字段类型
		ProductName string    `json:"product_name,omitempty"`
		Quantity    uint      `json:"quantity,omitempty"`
		CostPoints  int       `json:"cost_points,omitempty"` // 商品订单消耗积分
		GetPoints   int       `json:"get_points,omitempty"`  // 积分订单获得积分
		OrderNo     string    `json:"order_no,omitempty"`
		Amount      float64   `json:"amount,omitempty"`
		Status      string    `json:"status,omitempty"`
		CreatedAt   time.Time `json:"created_at"`
	}
	var (
		items []OrderItem
		total int64
		err   error
	)
	switch req.Type {
	case "product":
		var purchases []configs.Purchase
		query := configs.DB.Model(&configs.Purchase{}).Preload("Product").Where("user_id = ?", currentUser.ID).Order("created_at DESC")
		if err = query.Count(&total).Error; err != nil {
			JsonResponse(c, http.StatusInternalServerError, "查询商品订单失败", nil)
			return
		}
		if err = query.Scopes(configs.Paginate(req.Page, req.PageSize)).Find(&purchases).Error; err != nil {
			JsonResponse(c, http.StatusInternalServerError, "获取商品订单失败", nil)
			return
		}
		for _, p := range purchases {
			items = append(items, OrderItem{
				ID:          p.ID,
				OrderType:   "product",
				ProductName: p.Product.Name,
				Quantity:    p.Quantity,
				CostPoints:  int(p.Product.Points * p.Quantity),
				CreatedAt:   p.CreatedAt,
			})
		}
	case "points":
		var orders []configs.Order
		query := configs.DB.Model(&configs.Order{}).Where("user_id = ?", currentUser.ID).Order("created_at DESC")
		if err = query.Count(&total).Error; err != nil {
			JsonResponse(c, http.StatusInternalServerError, "查询积分订单失败", nil)
			return
		}
		if err = query.Scopes(configs.Paginate(req.Page, req.PageSize)).Find(&orders).Error; err != nil {
			JsonResponse(c, http.StatusInternalServerError, "获取积分订单失败", nil)
			return
		}
		for _, o := range orders {
			items = append(items, OrderItem{
				ID:         o.ID,
				OrderType:  "points",
				OrderNo:    o.OrderNo,
				Amount:     o.Amount,
				GetPoints:  o.Points, // 确保这里使用正确的字段
				Status:     string(o.Status),
				CreatedAt:  o.CreatedAt,
			})
		}
	}
	JsonResponse(c, http.StatusOK, "Success", gin.H{
		"items":    items,
		"total":    total,
		"page":     req.Page,
		"pageSize": req.PageSize,
	})
}